package com.zqwh.yj.sdk.model;

import com.gg.reader.api.dal.GClient;
import com.gg.reader.api.dal.HandlerTagEpcLog;
import com.gg.reader.api.dal.HandlerTagEpcOver;
import com.gg.reader.api.protocol.gx.EnumG;
import com.gg.reader.api.protocol.gx.LogBaseEpcInfo;
import com.gg.reader.api.protocol.gx.LogBaseEpcOver;
import com.gg.reader.api.protocol.gx.MsgBaseInventoryEpc;
import com.gg.reader.api.protocol.gx.MsgBaseSetPower;
import com.gg.reader.api.protocol.gx.MsgBaseStop;
import com.zqwh.yj.sdk.obj.AntConfig;
import com.zqwh.yj.sdk.utils.CountDownTimerUtil;
import com.zqwh.yj.sdk.utils.LogUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Created by eason.yang on 2019/8/15.
 */

public class RfidGx16ModelImpl implements RfidModel{
    private final static int INV_STATE_IDLE = 0;
    private final static int INV_STATE_ING = 1;
    private final static int INV_STATE_WAIT = 2;

    private int mInvState = INV_STATE_IDLE;

    private Map<String, Integer[]> mTagsMap = new LinkedHashMap<>();
    private int mAntId;
    private int mStartAntId;
    private int mEndAntId;
    private int mInventoryTime;
    private InventoryListener mInventoryTagListener;
    private CountDownTimerUtil mTimeCounter;
    private int mTickCount = 0;
    private int mMaxAntNumber;
    private int mAntNumber;
    private String mUartPath;
    private int mBaudRate;
    private int mRfPower;
    private int[] mRfPowerArray;
    private List<AntConfig> mAntConfigs;
    private GClient mGClient = GlobalClient.getClient();
    private MsgBaseStop mMsgBaseStop = null;

    public RfidGx16ModelImpl(int maxAntNumber, int antNumber, String uartPath, int baudRate, int rfPower) {
        this.mMaxAntNumber = maxAntNumber;
        this.mAntNumber = antNumber;
        this.mUartPath = uartPath;
        this.mBaudRate = baudRate;
        this.mRfPower = rfPower;
    }

    public RfidGx16ModelImpl(int maxAntNumber, int antNumber, String uartPath, int baudRate, int[] rfPowerArray) {
        this.mMaxAntNumber = maxAntNumber;
        this.mAntNumber = antNumber;
        this.mUartPath = uartPath;
        this.mBaudRate = baudRate;
        this.mRfPowerArray = rfPowerArray;
    }

    @Override
    public int setAntConfigs(List<AntConfig> antConfigs) {
        mAntConfigs = antConfigs;
        return 0;
    }

    @Override
    public int connectSerialPort() {
        if (mGClient.openAndroidSerial(mUartPath+":"+mBaudRate, 1000)){
            mGClient.onTagEpcLog = new HandlerTagEpcLog() {
                @Override
                public void log(String readName, LogBaseEpcInfo logBaseEpcInfo) {
                    // 回调内部如有阻塞，会影响API正常使用
                    // 标签回调数量较多，请将标签数据先缓存起来再作业务处理
                    if (null != logBaseEpcInfo && 0 == logBaseEpcInfo.getResult() ) {
                        if (mInvState == INV_STATE_ING) {
                            Integer[] findEpcInfo = mTagsMap.get(logBaseEpcInfo.getEpc());
                            if (findEpcInfo == null) {
                                Integer[] epcInfo = new Integer[mMaxAntNumber];
                                for (int i = 0; i < epcInfo.length; i++){
                                    epcInfo[i] = 0;
                                }
                                epcInfo[logBaseEpcInfo.getAntId() - 1] += 1;
                                mTagsMap.put(logBaseEpcInfo.getEpc(), epcInfo);
                                if (mInventoryTagListener != null) {
                                    mInventoryTagListener.onInventoryChanged(mTagsMap.size(), logBaseEpcInfo.getEpc(), logBaseEpcInfo.getAntId());
                                }
                            }else {
                                findEpcInfo[logBaseEpcInfo.getAntId() - 1] += 1;
                            }
                            if (mInventoryTagListener != null) {
                                mInventoryTagListener.onInventoryOnce(logBaseEpcInfo.getEpc(), logBaseEpcInfo.getAntId());
                            }
                        }
                    }
                }
            };
            mGClient.onTagEpcOver = new HandlerTagEpcOver() {
                @Override public void log(String s, LogBaseEpcOver logBaseEpcOver) {
                    if (null != logBaseEpcOver) {
                        if (logBaseEpcOver.getRtCode() == 0){
                            //单次盘点完成
                        }else if (logBaseEpcOver.getRtCode() == 1){
                            //接收到停止盘点指令
                        }else if (logBaseEpcOver.getRtCode() == 2){
                            //硬件错误
                            if (mInventoryTagListener != null){
                                mInventoryTagListener.onInventoryError("盘点失败，检测到硬件状态异常");
                            }
                        }
                        LogUtils.logout(logBaseEpcOver.getRtMsg());
                    }
                }
            };

            // 停止指令，空闲态
            MsgBaseStop msgBaseStop = new MsgBaseStop();
            mGClient.sendSynMsg(msgBaseStop);
            if (0 == msgBaseStop.getRtCode()) {
                LogUtils.logout("Inventory stop successful.");
            } else {
                LogUtils.error("Inventory stop fail.");
            }

            MsgBaseSetPower msgBaseSetPower = new MsgBaseSetPower();
            Hashtable<Integer, Integer> hashtable = new Hashtable<>();
            if (mAntConfigs == null){
                for (Integer ant = 1; ant <= mMaxAntNumber; ant ++){
                    if (mRfPowerArray != null && mRfPowerArray.length != 0){
                        LogUtils.logout("Set ant " + ant + " power "+ mRfPowerArray[ant - 1]);
                        hashtable.put(ant, mRfPowerArray[ant - 1]);
                    }else {
                        LogUtils.logout("Set ant " + ant + " power "+mRfPower);
                        hashtable.put(ant, mRfPower);
                    }
                }
            } else {
                for (AntConfig antConfig: mAntConfigs){
                    if (antConfig.isEnable()){
                        LogUtils.logout("Set ant " + antConfig.getAntId() + " power "+antConfig.getPower());
                        hashtable.put(antConfig.getAntId(), antConfig.getPower());
                    }
                }
            }
//            hashtable.put(mMaxAntNumber, mRfPower);
            msgBaseSetPower.setDicPower(hashtable);
            mGClient.sendSynMsg(msgBaseSetPower);
            if (0 == msgBaseSetPower.getRtCode()) {
                LogUtils.logout("Power configuration successful.");
                return 0;
            }else {
                LogUtils.error("Power configuration fail.");
                return -2;
            }
        }else {
            return -1;
        }
    }

    @Override
    public int startInventoryTag(final int antId, final int inventoryTime, InventoryListener listener) {
        mAntId = antId;
        mInventoryTime = inventoryTime;
        mInventoryTagListener = listener;
        mTimeCounter = new CountDownTimerUtil(mInventoryTime, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                if(mTickCount != 0) {
                    mInventoryTagListener.onInventoryTick(mTickCount, mTagsMap.size());
                }
                mTickCount = mTickCount + 1;
            }

            @Override
            public void onFinish() {
                stopInventoryTag();
                List<String> tagListTmp = new ArrayList<>();
                for (String epc : mTagsMap.keySet()) {
                    StringBuilder log = new StringBuilder("epc=" + epc + " : ");
                    int maxAnt = 1;
                    int maxCount = 0;
                    for (int i = 0; i < Objects.requireNonNull(mTagsMap.get(epc)).length; i++){
                        int antNum = i + 1;
                        int inventoryCount = Objects.requireNonNull(mTagsMap.get(epc))[i];
                        if (maxCount < inventoryCount){
                            maxCount = inventoryCount;
                            maxAnt = antNum;
                        }
                        log.append(", ").append(antNum).append("=").append(inventoryCount);
                    }
                    tagListTmp.add(epc+"#"+maxAnt);
                }
                mInventoryTagListener.onInventoryTagFinish(tagListTmp);
                mTickCount = 0;
            }
        };
        if (mInvState == INV_STATE_IDLE) {
            mTagsMap.clear();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
                    long antennaEnable = (long) getAnt(mAntId);
                    msgBaseInventoryEpc.setAntennaEnable(antennaEnable);
                    msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Inventory);
                    mGClient.sendSynMsg(msgBaseInventoryEpc);
                    mInvState = INV_STATE_ING;
                    mTimeCounter.start();
                    if (0x00 == msgBaseInventoryEpc.getRtCode()) {
                        LogUtils.logout("Inventory start successful.");
                    } else {
                        LogUtils.error("Inventory start fail.");
                    }
                }
            }).start();
            return 0;
        }else {
            return -1;
        }
    }

    @Override
    public int startInventoryTag(final int startAntId, final int endAntId, final int inventoryTime, InventoryListener listener) {
        mStartAntId = startAntId;
        mEndAntId = endAntId;
        mInventoryTime = inventoryTime;
        mInventoryTagListener = listener;
        mTimeCounter = new CountDownTimerUtil(mInventoryTime, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                if(mTickCount != 0) {
                    mInventoryTagListener.onInventoryTick(mTickCount, mTagsMap.size());
                }
                mTickCount = mTickCount + 1;
            }

            @Override
            public void onFinish() {
                stopInventoryTag();
                List<String> tagListTmp = new ArrayList<>();
                for (String epc : mTagsMap.keySet()) {
                    StringBuilder log = new StringBuilder("epc=" + epc + " : ");
                    int maxAnt = 1;
                    int maxCount = 0;
                    for (int i = 0; i < Objects.requireNonNull(mTagsMap.get(epc)).length; i++){
                        int antNum = i + 1;
                        int inventoryCount = Objects.requireNonNull(mTagsMap.get(epc))[i];
                        if (maxCount < inventoryCount){
                            maxCount = inventoryCount;
                            maxAnt = antNum;
                        }
                        log.append(", ").append(antNum).append("=").append(inventoryCount);
                    }
                    tagListTmp.add(epc+"#"+maxAnt);
                }
                mInventoryTagListener.onInventoryTagFinish(tagListTmp);
                mTickCount = 0;
            }
        };
        if (mInvState == INV_STATE_IDLE) {
            mTagsMap.clear();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
                    long antennaEnable = (long) getAnt(mStartAntId, mEndAntId);
                    msgBaseInventoryEpc.setAntennaEnable(antennaEnable);
                    msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Inventory);
                    mGClient.sendSynMsg(msgBaseInventoryEpc);
                    mInvState = INV_STATE_ING;
                    mTimeCounter.start();
                    if (0x00 == msgBaseInventoryEpc.getRtCode()) {
                        LogUtils.logout("Inventory start successful.");
                    } else {
                        LogUtils.error("Inventory start fail.");
                    }
                }
            }).start();
            return 0;
        }else {
            return -1;
        }
    }

    public void finishInventoryTag(){
        mTimeCounter.onFinish();
    }

    @Override
    public int startInventoryTag(int inventoryTime, InventoryListener listener) {
        mInventoryTime = inventoryTime;
        mInventoryTagListener = listener;
        mTimeCounter = new CountDownTimerUtil(mInventoryTime, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                if(mTickCount != 0) {
                    mInventoryTagListener.onInventoryTick(mTickCount, mTagsMap.size());
                }
                mTickCount = mTickCount + 1;
            }

            @Override
            public void onFinish() {
                LogUtils.logout("finish..");
                stopInventoryTag();
                List<String> tagListTmp = new ArrayList<>();
                for (String epc : mTagsMap.keySet()) {
                    StringBuilder log = new StringBuilder("epc=" + epc + " : ");
                    int maxAnt = 1;
                    int maxCount = 0;
                    for (int i = 0; i < Objects.requireNonNull(mTagsMap.get(epc)).length; i++){
                        int antNum = i + 1;
                        int inventoryCount = Objects.requireNonNull(mTagsMap.get(epc))[i];
                        if (maxCount < inventoryCount){
                            maxCount = inventoryCount;
                            maxAnt = antNum;
                        }
                        log.append(", ").append(antNum).append("=").append(inventoryCount);
                    }
//                    LogUtils.logout(log.toString());
                    tagListTmp.add(epc+"#"+maxAnt);
                }
                mInventoryTagListener.onInventoryTagFinish(tagListTmp);
                mTickCount = 0;
            }
        };
        if (mInvState == INV_STATE_IDLE) {
            mTagsMap.clear();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
                    long antennaEnable;
                    if (mAntConfigs == null) {
                        antennaEnable = (long) getAnt();
                    } else {
                        antennaEnable = (long) getAnt(mAntConfigs);
                    }
                    LogUtils.logout("Inventory ant enable : " + Long.toBinaryString(antennaEnable));
                    msgBaseInventoryEpc.setAntennaEnable(antennaEnable);
                    msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Inventory);
                    mGClient.sendSynMsg(msgBaseInventoryEpc);
                    mInvState = INV_STATE_ING;
                    mTimeCounter.start();
                    int ret = msgBaseInventoryEpc.getRtCode();
                    if (0x00 == ret) {
                        LogUtils.logout("Inventory start successful.");
                    } else {
                        LogUtils.error("Inventory start fail."+ret);
                    }
                }
            }).start();
            return 0;
        }else {
            return -1;
        }
    }

    @Override
    public int stopInventoryTag() {
        LogUtils.logout("stop..");
        mInvState = INV_STATE_WAIT;
        // 停止指令，空闲态
        if (mTimeCounter != null) {
            mTimeCounter.cancel();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (mMsgBaseStop == null){
                    mMsgBaseStop = new MsgBaseStop();
                }
                mInvState = INV_STATE_IDLE;
                mGClient.sendSynMsg(mMsgBaseStop);
                if (0 == mMsgBaseStop.getRtCode()) {
                    LogUtils.logout("Inventory stop successful.");
                } else {
                    LogUtils.error("Inventory stop fail.");
                }
            }
        }).start();
        return 0;
    }

    //获取天线
    private int getAnt() {
        StringBuilder buffer = new StringBuilder();
        for (int ant = mMaxAntNumber; ant >= 1; ant --) {
            if (ant <= mAntNumber) {
                buffer.append(1);
            } else {
                buffer.append(0);
            }
        }
        return Integer.parseInt(buffer.toString(), 2);
    }

    private int getAnt(int startAntId, int endAntId){
        StringBuilder buffer = new StringBuilder();
        for (int ant = mMaxAntNumber; ant >= 1; ant --) {
            if (ant >= startAntId && ant <= endAntId) {
                buffer.append(1);
            } else {
                buffer.append(0);
            }
        }
        return Integer.parseInt(buffer.toString(), 2);
    }

    private int getAnt(int antId){
        StringBuilder buffer = new StringBuilder();
        for (int ant = mMaxAntNumber; ant >= 1; ant --) {
            if (ant == antId) {
                buffer.append(1);
            } else {
                buffer.append(0);
            }
        }
        return Integer.parseInt(buffer.toString(), 2);
    }

    private int getAnt(List<AntConfig> antConfigs){
        StringBuilder buffer = new StringBuilder();
        List<AntConfig> temp = new ArrayList<>(antConfigs);
        Collections.reverse(temp);
        for (AntConfig antConfig: temp){
            if (antConfig.isEnable()){
                buffer.append(1);
            }else {
                buffer.append(0);
            }
        }
        return Integer.parseInt(buffer.toString(), 2);
    }

    @Override
    public String getAllAntSWR() {
        return "";
    }

    @Override
    public int getRfidStatus() {
        return 0;
    }
}
